using System;
using System.Windows.Input;
using WpfWordsLearner.Helper;
using System.Collections.Generic;
using System.Windows;
using System.Linq;
using System.Collections.ObjectModel;
using System.Xml.Linq;

namespace WpfWordsLearner.ViewModels
{
	public class Windows1ViewModel : BaseViewModel
	{
		private ObservableCollection<Model.WordsModel> m_words = null;
		private ObservableCollection<Model.WordsModel> m_previousState = null;
		private int m_searchCount = 0;
		private int m_wordCount = 0;

		private Dictionary<int, ObservableCollection<Model.WordsModel>> m_changes = null;
		private ObservableCollection<Model.DirectoryModel> dirModel = null;

		public Windows1ViewModel()
		{
			m_changes = new Dictionary<int, ObservableCollection<Model.WordsModel>>();

			m_words = WordsManager.Instance.GetWordsList();
			WordsCount = m_words.Count;
			ComplicatedCount = m_words.Where(x => x.IsComplicated).Count();

			m_changes.Add(m_searchCount, m_words);

			DirectoryModels = new ObservableCollection<Model.DirectoryModel>();

			var model = new Model.DirectoryModel();
			RecursiveIO(App.pathToContent, ref model);

			DirectoryModels.Add(model);

			System.Threading.Tasks.Task.Factory.StartNew(() => InitializeWatcher());
		}

		public ObservableCollection<Model.DirectoryModel> DirectoryModels
		{
			get { return dirModel; }
			set { dirModel = value; OnPropertyChanged(() => DirectoryModels); }
		}

		private System.IO.FileSystemWatcher m_watcher = null;
		private System.Windows.Threading.Dispatcher m_disp = null;

		public void SetDispatcher(System.Windows.Threading.Dispatcher disp)
		{
			m_disp = disp;
		}

		private void InitializeWatcher()
		{
			m_watcher = new System.IO.FileSystemWatcher(App.pathToContent);
			m_watcher.BeginInit();
			m_watcher.Path = App.pathToContent;
			m_watcher.Filter = "*.xml";
			m_watcher.IncludeSubdirectories = false;
			m_watcher.NotifyFilter = System.IO.NotifyFilters.LastWrite | System.IO.NotifyFilters.FileName | System.IO.NotifyFilters.Size | System.IO.NotifyFilters.DirectoryName;
			m_watcher.Created += new System.IO.FileSystemEventHandler(watcher_Changed);
			m_watcher.Deleted += new System.IO.FileSystemEventHandler(watcher_Changed);
			m_watcher.Changed += new System.IO.FileSystemEventHandler(watcher_Changed);
			m_watcher.EndInit();

			m_watcher.EnableRaisingEvents = true;
		}

		void watcher_Changed(object sender, System.IO.FileSystemEventArgs e)
		{
			switch (e.ChangeType)
			{
				case System.IO.WatcherChangeTypes.Created:
					var fi = new System.IO.FileInfo(e.FullPath);
					if (fi.Exists && fi.Extension.Contains("xml"))
					{
						var model = new Model.FileModel();
						model.FullPath = e.FullPath;
						model.Name = e.Name;
						model.Lenght = fi.Length;
						m_disp.BeginInvoke(new Action(() =>
						{
							DirectoryModels[0].Children.Add(model);
						}));
						fi = null;
					}
					break;

				case System.IO.WatcherChangeTypes.Deleted:
					Model.IBaseIO based = DirectoryModels[0].Children.FirstOrDefault(x => string.Compare(x.Name, e.Name, false) == 0);
					if (based != null && based is Model.FileModel)
					{
						m_disp.BeginInvoke(new Action(() =>
						{
							DirectoryModels[0].Children.Remove(based);
						}));

						System.IO.File.Delete(e.FullPath);
					}
					break;

				case System.IO.WatcherChangeTypes.Changed:
					break;

				default:
					break;
			}
		}

		private void RecursiveIO(string fPath, ref Model.DirectoryModel model)
		{
			var di = new System.IO.DirectoryInfo(fPath);
			model.FullPath = di.FullName;
			model.Name = di.Name;

			foreach (System.IO.FileInfo file in new System.IO.DirectoryInfo(model.FullPath).EnumerateFiles("*.xml", System.IO.SearchOption.TopDirectoryOnly))
			{
				model.Children.Add(new Model.FileModel() { Name = file.Name, FullPath = file.FullName, Lenght = file.Length });
			}

			foreach (string dir in System.IO.Directory.EnumerateDirectories(model.FullPath))
			{
				Model.DirectoryModel subDir = new Model.DirectoryModel();
				subDir.FullPath = dir;
				subDir.Name = System.IO.Path.GetDirectoryName(dir);
				RecursiveIO(dir, ref subDir);
				model.Children.Add(subDir);
			}
		}

		private Model.IBaseIO m_selDict;
		public Model.IBaseIO SelectedDictionary
		{
			get { return m_selDict; }
			set
			{
				m_selDict = value; OnPropertyChanged(() => SelectedDictionary);
			}
		}

		public ObservableCollection<WpfWordsLearner.Model.WordsModel> Words
		{
			get { return m_words; }
			set
			{
				m_words = value;
				OnPropertyChanged(() => Words);
				if (Words != null)
					ComplicatedCount = Words.Where(x => x.IsComplicated = true).Count();
			}
		}

		private string m_selXmlDictionaty;
		public string SelectedXML
		{
			get { return m_selXmlDictionaty; }
			set { m_selXmlDictionaty = value; OnPropertyChanged(() => SelectedXML); }
		}

		public int SearchCount
		{
			get { return m_searchCount; }
			set { m_searchCount = value; OnPropertyChanged(() => SearchCount); }
		}

		public int WordsCount
		{
			get
			{
				return m_wordCount;
			}
			set
			{
				m_wordCount = value;
				OnPropertyChanged(() => WordsCount);
			}
		}

		private Model.WordsModel selWwORD;

		public Model.WordsModel SelectedWord
		{
			get { return selWwORD; }
			set { selWwORD = value; }
		}

		private int compCount;

		public int ComplicatedCount
		{
			get { return compCount; }
			set { compCount = value; OnPropertyChanged(() => ComplicatedCount); }
		}

		#region Commands implementation
		public ICommand ClickCommand { get { return new BaseCommand(Click); } }
		private void Click()
		{
			Views.AddWordsView add = new Views.AddWordsView();
			add.Owner = App.Current.MainWindow;
			add.WindowStartupLocation = WindowStartupLocation.CenterOwner;

			if (add.ShowDialog() == true)
			{
				Words = WordsManager.Instance.GetWordsList();
				WordsCount = Words.Count;
			}
		}

		public ICommand ExitCommand { get { return new BaseCommand(ExitExecuted); } }
		private void ExitExecuted()
		{
			App.Current.Shutdown();
		}

		public ICommand AddWordRangeCommand { get { return new BaseCommand(AddWordRangeExecuted); } }
		private void AddWordRangeExecuted()
		{
			Views.AddWordsRangeView addRange = new Views.AddWordsRangeView();
			if (addRange.ShowDialog() == true)
			{
				Words = WordsManager.Instance.GetWordsList();
				WordsCount = Words.Count;
			}
		}

		public ICommand BeginTetsCommand { get { return new BaseCommand(TestExecuted); } }
		private void TestExecuted()
		{
			Views.TestSettingView testSettingsView = new Views.TestSettingView();
			testSettingsView.Owner = App.Current.MainWindow;
			testSettingsView.WindowStartupLocation = System.Windows.WindowStartupLocation.CenterScreen;
			testSettingsView.Show();
		}

		public ICommand FindCommand { get { return new BaseCommand(FilterByWords); } }
		public void FilterByWords()
		{
			Window wind = App.Current.Windows.Cast<Window>().FirstOrDefault(window => window.IsActive);
			Views.SearchView sw = new Views.SearchView();
			sw.Owner = wind;
			sw.WindowStartupLocation = WindowStartupLocation.CenterOwner;
			if (sw.ShowDialog() == true)
			{
				m_previousState = Words;
				Words = new ObservableCollection<Model.WordsModel>(Words.Select(m => m).Where(m => m.EnglishWord.ToLower().Contains(sw.SearchParam.ToLower().Trim())));
				SearchCount++;
				if (m_changes.ContainsKey(m_searchCount))
					m_changes[m_searchCount] = Words;
				else
					m_changes.Add(m_searchCount, Words);

				WordsCount = Words.Count;
			}
		}

		public ICommand ReturnBackCommand { get { return new BaseCommand(ReturnBack); } }
		public void ReturnBack()
		{
			if (m_searchCount == 0)
				return;

			SearchCount--;
			Words = m_changes[m_searchCount];
			WordsCount = Words.Count;
		}

		public ICommand UndoCommand { get { return new BaseCommand(Undo); } }
		public void Undo()
		{
			if (m_searchCount == m_changes.Count - 1)
				return;

			SearchCount++;
			Words = m_changes[SearchCount];
			WordsCount = Words.Count;
		}

		public ICommand ExportCommand { get { return new BaseCommand(Export); } }
		public void Export()
		{
			Views.ExportView exportView = new Views.ExportView();
			exportView.Owner = App.Current.MainWindow;
			exportView.Show();
		}

		public ICommand ImportCommand { get { return new BaseCommand(Import); } }
		private void Import()
		{
			Views.ImportView importView = new Views.ImportView();
			importView.Owner = App.Current.MainWindow;
			importView.Closing += (sender, arg) =>
			{
				if (sender is Views.ImportView && (sender as Views.ImportView).IsImported)
				{
					Words.Clear();
					Words = null;
					GC.Collect(0);

					Words = WordsManager.Instance.GetWordsList();
					WordsCount = Words.Count;
				}
			};

			importView.Show();
		}

		public ICommand MarkComplicated { get { return new BaseCommand(Mark); } }
		private void Mark()
		{
			if (SelectedWord != null)
			{
				SelectedWord.IsComplicated = true;
			}
		}

		public ICommand UnmarkComplicated { get { return new BaseCommand(Unmark); } }
		private void Unmark()
		{
			if (SelectedWord != null)
			{
				SelectedWord.IsComplicated = false;
			}
		}

		public ICommand SelectWordsCommand { get { return new BaseCommand(SelectWordsExec); } }
		private void SelectWordsExec()
		{
			ViewModels.WordsSelectorViewModel vm = new WordsSelectorViewModel();

			Views.WordsSelectionView view = new Views.WordsSelectionView();
			view.DataContext = vm;
			view.Owner = App.Current.MainWindow;
			view.ShowActivated = true;
			view.ShowDialog();

			vm.Dispose();
		}

		public ICommand DeleteDictionaryCommand { get { return new BaseCommand(DeleteDictionary); } }
		private void DeleteDictionary()
		{
			if (SelectedDictionary != null && SelectedDictionary is Model.FileModel &&
				MessageBox.Show(WpfWordsLearner.Properties.Resources.msgDeleteConfirmation, WpfWordsLearner.Properties.Resources.msgDeleteConfTitle, MessageBoxButton.YesNo,
				MessageBoxImage.Question) == MessageBoxResult.Yes)
			{
				try
				{
					System.IO.File.Delete((SelectedDictionary as Model.FileModel).FullPath);
					this.DirectoryModels[0].Children.Remove(SelectedDictionary);
				}
				catch (System.IO.IOException ex) { ShowMessageBox(ex.Message); }
			}
		}

		public ICommand LoadDictionaryCommand { get { return new BaseCommand(LoadDictionary); } }
		private void LoadDictionary()
		{
			if (SelectedDictionary != null && SelectedDictionary is Model.FileModel)
			{
				ComplicatedCount = Words.Where(x => x.IsComplicated).Count();

				Words.Clear();
				Words = null;

				WordsManager.Instance.SetPreference((SelectedDictionary as Model.FileModel).FullPath);
				Words = WordsManager.Instance.GetWordsList();

				this.m_changes.Clear();
				SelectedXML = (SelectedDictionary as Model.FileModel).FullPath;
				GC.Collect(0);
			}
		}

		public ICommand SaveDictionaryCommand { get { return new BaseCommand(SaveDictinary); } }
		private void SaveDictinary()
		{
			if (SelectedDictionary != null && SelectedDictionary is Model.FileModel &&
				MessageBox.Show(WpfWordsLearner.Properties.Resources.msgSaveConfirm, WpfWordsLearner.Properties.Resources.msgSaveConfTitle, MessageBoxButton.YesNo,
				MessageBoxImage.Question) == MessageBoxResult.Yes)
			{
				ComplicatedCount = Words.Where(x => x.IsComplicated).Count();

				WordsManager.Instance.WordsToSave = Words.ToList();
				WordsManager.Instance.FinalSave();

				WordsManager.Instance.WordsToSave = null;
				GC.Collect(0);

			}
			else if (SelectedDictionary != null && SelectedDictionary is Model.DirectoryModel)
			{
				ShowMessageBox(WpfWordsLearner.Properties.Resources.failPerformAction);
			}
		}

		public ICommand CompressCommand { get { return new BaseCommand(Compress); } }
		private void Compress()
		{
			if (!(SelectedDictionary is Model.DirectoryModel))
			{
				base.ShowMessageBox(WpfWordsLearner.Properties.Resources.msgActionrestricted);
				return;
			}

			try
			{
				CompressionModule module = new CompressionModule();
				string file = System.IO.Path.Combine(DirectoryModels[0].FullPath, string.Format("{0}.zip", DateTime.Now.ToString("dd-MM-yy hh-mm")));
				module.Compress(DirectoryModels[0].FullPath, file);

				System.Diagnostics.Process.Start("explorer.exe", DirectoryModels[0].FullPath);
			}
			catch (Exception ex) { ShowMessageBoxError(ex.Message); App.Log.Error(WpfWordsLearner.Properties.Resources.failCompress, ex); }
		}

		public ICommand MergeCommand { get { return new BaseCommand(MergeExc); } }
		private void MergeExc()
		{
			UncompressVM vm = new UncompressVM();
			Views.DecompressAndMergeWind view = new Views.DecompressAndMergeWind();
			view.Owner = App.Current.MainWindow;
			view.DataContext = vm;
			view.WindowStartupLocation = WindowStartupLocation.CenterOwner;
			view.WindowStyle = WindowStyle.ToolWindow;
			view.ShowDialog();
		}

		public ICommand CloseCommand { get { return new BaseCommand(CloseWind); } }
		private void CloseWind()
		{
			WordsManager.Instance.WordsToSave = Words.ToList();
		}

		public ICommand PlaySoundCommand { get { return new BaseCommand(SoundPlay); } }

		private void SoundPlay()
		{
			if (SelectedWord != null)
			{
				System.Threading.Tasks.Task.Factory.StartNew(new Action(() =>
					{
						using (VoiceManager2 manager = new VoiceManager2())
						using (ServiceReferenceTranslater.TranslateServiceClient client = new ServiceReferenceTranslater.TranslateServiceClient())
						using (DAO.WordsDaoPlain plain = new DAO.WordsDaoPlain(App.pathToDB))
						{
							string wordToVoiced = null;

							m_disp.BeginInvoke(new Action(() => wordToVoiced = SelectedWord.EnglishWord),
								System.Windows.Threading.DispatcherPriority.Normal).Wait(TimeSpan.FromMilliseconds(200));

							if (plain.IsWordVoiced(wordToVoiced))
							{
								byte[] data = plain.GetVoiceForWord(wordToVoiced);
								if (data != null)
								{
									System.IO.Stream sr = new System.IO.MemoryStream(data);
									manager.Play(sr);
									System.Threading.Thread.Sleep(500);
									sr.Dispose();
								}
							}
							else
							{
								var req = new ServiceReferenceTranslater.VoiceRequest();
								req.ToLanguage = "en";
								req.OriginalText = wordToVoiced;
								ServiceReferenceTranslater.VoiceResponse response = null;
								try
								{
									response = client.GetVoice(req);
									if (response != null && response.Data != null)
									{
										plain.AddVoicedWord(req.OriginalText, response.Data);
										System.IO.Stream sr = new System.IO.MemoryStream(response.Data);
										manager.Play(sr);
										System.Threading.Thread.Sleep(500);
										sr.Dispose();
									}
								}
								catch (System.ServiceModel.FaultException<ServiceReferenceTranslater.VoiceFault> ex)
								{
									App.Log.Error(WpfWordsLearner.Properties.Resources.failVoice, ex);
								}
							}
						}
					})).ContinueWith(prevTask =>
					{
						App.Log.Error(WpfWordsLearner.Properties.Resources.failVoice, prevTask.Exception.Flatten());
						prevTask.Dispose();
					}, System.Threading.Tasks.TaskContinuationOptions.NotOnRanToCompletion);
			}
		}

		public ICommand HandleKeyFCommand { get { return new Catel.MVVM.Command(HandleKeyF); } }
		private void HandleKeyF()
		{
			(App.Current.MainWindow.DataContext as Windows1ViewModel).FilterByWords();
		}

		public ICommand HandleKeyZCommand { get { return new Catel.MVVM.Command(HandleKeyZ); } }
		private void HandleKeyZ()
		{
			(App.Current.MainWindow.DataContext as Windows1ViewModel).ReturnBack();
		}

		public ICommand DropCommand { get { return new Catel.MVVM.Command<object>(DropHandler); } }
		private void DropHandler(object data)
		{
			if (data != null)
			{
				this.ShowMessageBox(string.Format(WpfWordsLearner.Properties.Resources.msgDrop, (data as Model.WordsModel).EnglishWord));
			}
		}

		public ICommand CreateNewDictionaryCommand { get { return new BaseCommand(CreateNewDict); } }
		private void CreateNewDict()
		{
			Views.NewDictionaryView view = new Views.NewDictionaryView();
			view.Owner = App.Current.MainWindow;
			ViewModels.NewDictionaryVM newVM = new NewDictionaryVM();
			view.DataContext = newVM;
			if (view.ShowDialog() == true)
			{

			}
		}
		#endregion

		#region for drag&drop
		private Point _startPoint;
		public Point StartPoint
		{
			get { return _startPoint; }
			set { _startPoint = value; OnPropertyChanged(() => StartPoint); }
		}

		private bool _isDragging;
		public bool IsDragging
		{
			get { return _isDragging; }
			set { _isDragging = value; OnPropertyChanged(() => IsDragging); }
		}
		#endregion
	}
}
